home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
t3_1
/
apollot.lha
/
apollot_sr10
/
tboot
/
boot_load.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1990-07-23
|
21KB
|
786 lines
PROGRAM boot_load;
%NOLIST;
%INCLUDE '/us/ins/ubase.ins.pas';
%INCLUDE '/sys/ins/time.ins.pas';
%INCLUDE '/sys/ins/cal.ins.pas';
%INCLUDE '/sys/ins/vfmt.ins.pas';
%INCLUDE '/sys/ins/error.ins.pas';
%INCLUDE '/sys/ins/pgm.ins.pas';
%INCLUDE '/sys/ins/name.ins.pas';
{ FROM /sys/ins/base.ins.pas - ??? }
CONST
ios_$max = 127; { [0..ios_$max] valid range for ios_$id_t when in use }
TYPE
ios_$id_t = 0..ios_$max; { open stream identifier }
ios_$seek_key_t = RECORD
rec_adr: integer32;
byte_adr: integer32;
END;
{ FROM /sys/ins/base.ins.pas - ??? }
%INCLUDE '/sys/ins/ios.ins.pas';
%INCLUDE '/us/ins/as.ins.pas'; { for as_$get_info }
%INCLUDE '/us/ins/loader.ins.pas'; { for pm_$load, kg_$lookup }
%INCLUDE '/us/ins/cl.ins.pas'; { for cl_$... }
%INCLUDE '/us/ins/lib.ins.pas'; { for lib_$data_move }
%INCLUDE '/us/ins/mst.ins.pas'; { for mst_$get_uid }
%INCLUDE '/us/ins/file.ins.pas'; { for file_$create, file_$delete_when_unlocked }
%INCLUDE '/us/ins/ms.ins.pas'; { for ms_$mapl_uid }
%LIST;
{*
PROCEDURE ms_$mk_temporary(
in va: univ_ptr;
out status: status_$t
); extern;
*}
PROCEDURE relocate
( count: linteger
; relocs: univ_ptr
; base: univ_ptr
; at: univ_ptr
);
VAL_PARAM; EXTERN;
{ from /us/com/las/las.pas }
CONST
machine_types = 8;
VAR
max_va: ARRAY [ -1..machine_types ] OF linteger
:= [ 16#03D00000
, 16#00D00000
, 16#00D00000
, 16#00D00000
, 16#00D00000
, 16#0F800000
, 16#00D00000
, 16#78000000
, 0
, 16#03B00000
];
CONST
hdr_size = 32; { Bad news: assumption about the amount of crud at
the top of UASC files }
VAR
debug: boolean;
verbose: boolean;
use_streams: boolean;
timing: boolean;
times: ARRAY[1..20] OF time_$clock_t;
time_nest: pinteger := 0;
PROCEDURE start_timing;
BEGIN
IF NOT timing THEN
RETURN;
time_nest := time_nest + 1;
time_$clock( times[ time_nest ] );
END;
PROCEDURE stop_timing
( IN s: string
);
VAR
t: time_$clock_t;
tf: double;
db: boolean;
BEGIN
IF NOT timing THEN
RETURN;
time_$clock( t );
db := cal_$sub_clock( t, times[ time_nest ] ) ;
cal_$float_clock( t, tf );
vfmt_$write2( s, 0, 0 );
vfmt_$write2( ' = %f%.', tf, 0 );
time_nest := time_nest - 1;
END;
PROCEDURE die
( IN str: string
; IN st: UNIV status_$t
);
BEGIN
vfmt_$write2( 'error loading t: %$', 0, 0 );
vfmt_$write2( str, 0, 0 );
vfmt_$write2( ' - %.', 0, 0 );
error_$print( st );
pgm_$exit();
END;
FUNCTION crtemp
( IN len: linteger
; OUT st: status_$t
)
: univ_ptr;
VAR
maplen: linteger;
p: univ_ptr;
xst: status_$t;
uid: uid_$t;
BEGIN
file_$create( uid_$nil, uid, st );
p := ms_$mapl_uid( uid, 0, len, ms_$nr_xor_1w, ms_$wrx, true, maplen, st );
file_$delete_when_unlocked( uid, xst );
crtemp := p;
END;
{
T object file format:
header
entry (relative offset in data section)
bytes of text relocation (each item is a four byte address to be relocated)
bytes of data relocation "
bytes of foreign relocation (each item is a four byte address followed by
a two byte size followed by characters)
size of text section (bytes)
size of data section (bytes)
text section
data section
text relocations
data relocations
xeno relocations
}
PROCEDURE load_t_object_file
( IN t_name: string
; IN t_namel: integer16
; OUT start_address: univ_ptr
; OUT data_address: univ_ptr
);
TYPE
memarray_t =
ARRAY [ 0 .. 1000000 ] OF linteger;
p_memarray_t =
^ memarray_t;
xeno_item_t =
RECORD
addr: linteger;
name: PACKED ARRAY [ 1..32 ] OF char; { blank padded, too! }
END;
p_xeno_item_t =
^ xeno_item_t;
header_t =
RECORD
entry: linteger;
text_reloc_size: linteger;
data_reloc_size: linteger;
foreign_size: linteger;
text_size: linteger;
data_size: linteger;
END;
VAR
header: header_t;
header_p: ^header_t;
d_at : ^string;
st: status_$t;
d_p,
t_p,
t_at,
r_at : univ_ptr;
len,
t_maplen,
r_maplen : linteger;
t_relocs,
d_relocs,
data_p : p_memarray_t;
xeno_p : p_xeno_item_t;
xeno_limit : linteger;
t_item_count,
d_item_count: linteger;
i,
ds_index : linteger;
relocation_size,
relocation_offset: linteger;
global_address: linteger;
id : ios_$id_t;
BEGIN
start_timing();
{ open object file }
{ use_streams vs. not: The logically correct way to copy the
impure data from the object file is via Streams.
Not only that, at sr9.5 it turns out to be better to slog the
data in via Streams, rather than by mapping the whole file
and doing one mongo data copy. This is because the latter
will result in more good pages being tossed from memory. Streams
does a piecewise copy -- mapping and copying piece of the file.
This will result in a minimal number of good pages pages being
tossed.
Unfortunately, due to a misfeature in Streams, the fact that
a "seek" occurs on the stream (to position to the impure data)
causes Streams to think that the file is being accessed
non-sequentially. As a result, Streams backs off some memory
management optimization (specifically "touch ahead") to something
less than the max value.
In the end, I couldn't decide whether the Streams or non-Streams
approach was better, so I left in both mechanisms. If/when
the Streams misfeature is fixed, "use_streams" mode should
be the only one, and the mapping code should be flushed from
here. }
IF use_streams THEN BEGIN
id := ios_$open( t_name, t_namel, [], st );
IF st.all <> 0 THEN
die( 'opening object file%$', st );
len := ios_$get( id, [ios_$no_rec_bndry_opt], header, sizeof( header ), st );
END
ELSE BEGIN
header_p := ms_$mapl( t_name, t_namel, hdr_size + 0, sizeof( header ), ms_$nr_xor_1w, ms_$rx
, false, len, st );
IF st.all <> 0 THEN
die( 'opening object file%$', st );
{ Copy header... }
ms_$advice( header_p, sizeof( header ), ms_$random, [], 0, st );
header := header_p^;
END;
IF verbose THEN
WITH header DO BEGIN
vfmt_$write5( ';Text = %d, data = %d, text reloc = %d, data reloc = %d%.',
text_size, data_size, text_reloc_size, data_reloc_size, 0 );
vfmt_$write2( ';Foreign_reloc_size = %d, entry = %LH%.',
foreign_size, entry );
END;
{ create map data section file }
d_at := crtemp( header.data_size, st );
IF st.all <> 0 THEN
die( 'creating/mapping data section temporary file%$', st );
ms_$advice( d_at, header.data_size, ms_$sequential, [], 0, st );
{ seek to data section }
IF use_streams THEN BEGIN
ios_$seek( id, ios_$absolute, ios_$byte_seek, sizeof( header ) + header.text_size, st );
start_timing();
len := ios_$get( id, [ios_$no_rec_bndry_opt], d_at^, header.data_size, st );
stop_timing( ';Time to copy data section%$' );
ios_$close( id, st );
{ map text section of object file }
t_at := ms_$mapl( t_name, t_namel, hdr_size + sizeof( header ), header.text_size, ms_$nr_xor_1w, ms_$rx
, false, len, st );
END
ELSE BEGIN
d_p := ms_$remap( header_p, hdr_size + sizeof( header ) + header.text_size, header.data_size, len, st );
IF st.all <> 0 THEN
die( 'seeking for data section%$', st );
{ ... and copy data section into mapped temporary file }
ms_$advice( d_p, header.data_size, ms_$sequential, [], 0, st );
start_timing();
lib_$data_move( d_p, d_at, header.data_size );
stop_timing( ';Time to copy data section%$' );
{ map text section of object file }
t_at := ms_$remap( d_p, hdr_size + sizeof( header ), header.text_size, t_maplen, st );
IF verbose OR debug THEN
vfmt_$write2( ';Text section_at: %LH%.', t_at, 0 );
END;
IF st.all <> 0 THEN
die( 'mapping procedure section%$', st );
IF debug THEN
BEGIN
{ read in text section }
t_p := t_at;
t_at := crtemp( header.text_size, st );
IF st.all <> 0 THEN
die( 'mapping writable text section temporary file%$', st );
lib_$data_move( t_p, t_at, header.text_size );
ms_$unmap( t_p, header.text_size, st );
END;
{ mark the pure text access pattern as being "random" }
ms_$advice( t_at, header.text_size, ms_$random, [], 0, st );
{ number of bytes of relocation information }
relocation_size := header.text_reloc_size
+ header.data_reloc_size
+ header.foreign_size;
{ offset from beginning of file to relocation information }
relocation_offset := sizeof( header ) + header.text_size + header.data_size;
{ map relocation information }
r_at := ms_$mapl( t_name, t_namel, hdr_size + relocation_offset, relocation_size
, ms_$nr_xor_1w, ms_$r, false, r_maplen, st );
IF verbose OR debug THEN
vfmt_$write2( 'relocation_size = %d%.',
relocation_size, 0 );
IF st.all <> 0 THEN
die( 'mapping relocation information%$', st );
{ t_items are offsets in the data section where the address of
the text section must be added; analogously for d_items }
t_item_count := header.text_reloc_size DIV 4;
d_item_count := header.data_reloc_size DIV 4;
t_relocs := p_memarray_t( r_at );
d_relocs := p_memarray_t( linteger( r_at ) + header.text_reloc_size );
data_p := p_memarray_t( d_at ); { pointer to beginning of data section }
{ for each addr in t_reloc (d+addr) <- (d+addr) + t }
start_timing();
relocate( t_item_count, t_relocs, data_p, t_at );
stop_timing( ';Text relocation time%$' );
{ for each addr in d_reloc (d+addr) <- (d+addr) + d }
start_timing();
relocate( d_item_count, d_relocs, data_p, d_at );
stop_timing( ';Data relocation time%$' );
{ for each addr, name in f_reloc (d+addr) <- lookup(name) }
IF verbose OR debug THEN
vfmt_$write2( 'relocation_size = %d%.',
relocation_size, 0 );
xeno_p := p_xeno_item_t( linteger( d_relocs ) + header.data_reloc_size );
xeno_limit := linteger( r_at ) + relocation_size;
IF verbose OR debug THEN
vfmt_$write2( ';Foreign relocs at: (%LH, %LH)%.', xeno_p, xeno_limit );
IF verbose OR debug THEN
vfmt_$write2( ';r_at = %LH, relocation_size = %d%.',
r_at, relocation_size );
start_timing();
WHILE linteger( xeno_p ) < xeno_limit DO BEGIN
ds_index := xeno_p^.addr DIV 4;
global_address := linteger( kg_$lookup( xeno_p^.name ) );
data_p^[ds_index] := global_address;
IF global_address = 0 THEN
vfmt_$write2( ';Warning: global %A not found%.', xeno_p^.name, 32 );
xeno_p := p_xeno_item_t( linteger( xeno_p ) + sizeof( xeno_item_t ) );
END;
stop_timing( ';Foreign relocation time%$' );
start_address := univ_ptr( header.entry + linteger( d_at ) );
data_address := d_at;
IF verbose OR debug THEN
vfmt_$write2( ';Data section_at: %LH%.', d_at, 0 );
ms_$advice( d_at, header.data_size, ms_$random, [], 0, st );
stop_timing( ';Load time%$' );
END;
{ ------------------------------------------------------- Heap allocation }
{ the following use of unreleased stuff is only to determine the biggest
hole in the address space, so we have the freedom to allocate heaps
as big as that. I think this stuff is all localized to BIGGEST_HOLE and
MACHINE_VAS }
FUNCTION machine_vas
: linteger;
TYPE
{ from /us/ins/md_if.ins.pas }
aux_info_t =
SET OF
( crash_eps { bit 0 => log_error, crash eps exist }
, m68020_board
); { bit 1 => M68020 }
{ from /us/ins/asknode.ins.pas }
asknode_$reply_t =
RECORD
version: pinteger;
kind : integer16;
status : status_$t;
CASE integer OF
0: (
config_valid_cnt: integer;
config_mach_id: integer;
config_aux_info: aux_info_t;
);
1: (
foo: ARRAY [ 1..25 ] OF integer;
);
END;
PROCEDURE asknode_$info
( IN kind: integer16
; IN x
, y: linteger
; OUT reply: asknode_$reply_t
; OUT status: status_$t
);
EXTERN;
VAR
status: status_$t;
reply: asknode_$reply_t;
{ from /sources/us/com/las/las.pas }
my_machine: integer;
BEGIN
asknode_$info( 39, 0, 0, reply, status );
IF status.all <> status_$ok THEN
my_machine := 1
ELSE
my_machine := reply.config_mach_id;
IF my_machine > machine_types THEN
BEGIN
vfmt_$write2( '%;Unknown machine type: %WD%.', my_machine, 0 );
my_machine := 1;
END;
IF my_machine IN [ 2, 3, 5 ] AND THEN
m68020_board IN reply.config_aux_info
THEN
my_machine := -1;
machine_vas := max_va[my_machine];
END;
{ scan address space to find biggest hole }
FUNCTION biggest_hole
: integer;
VAR
muid: uid_$t;
va,
start: linteger;
status: status_$t;
total,
max: integer;
max_va: linteger;
BEGIN
max_va := machine_vas();
va := 0;
max := 0;
total := 0;
WHILE va < max_va DO
BEGIN
mst_$get_uid( va, muid, start, status );
IF status.all <> 0 THEN
total := total + 1
ELSE
BEGIN
IF total > max THEN
max := total;
total := 0;
END;
va := va + seg_size;
END;
IF total > max THEN
max := total;
biggest_hole := max;
END;
PROCEDURE compute_heap_size
( heap_wanted
, leave_wanted: linteger
; heap_wanted_given
, leave_wanted_given: boolean
; OUT heap_size: linteger
);
CONST
min_heap_size = 16#80000; { 512K }
default_heap_size = 16#400000; { 4Mb }
minimum_leave = 16#80000; { 512K - to leave free after heap alloc }
VAR
max: linteger;
status: status_$t;
max_heap_size: linteger; { choosing heap size }
space_to_leave: linteger;
i: integer; { iteration }
BEGIN
IF leave_wanted_given THEN
space_to_leave := leave_wanted
ELSE
space_to_leave := minimum_leave + leave_wanted;
max := biggest_hole(); { maximum possible heap size }
max_heap_size := ((lshft( max, 15 ) - space_to_leave) DIV 2) & 16#FFFF8000; { 32k align }
IF (max_heap_size < min_heap_size) THEN
BEGIN
vfmt_$write2( 'Not enough space to allocate minimum heaps%.', 0 , 0 );
pgm_$exit;
END;
{ pick a heap size }
IF (NOT heap_wanted_given) THEN
IF default_heap_size < max_heap_size THEN
heap_size := default_heap_size
ELSE
heap_size := max_heap_size
ELSE
BEGIN
IF heap_wanted = 0 THEN
heap_wanted := max_heap_size;
heap_wanted := (heap_wanted + 16#7FFF) & 16#FFFF8000; { 32k align }
IF (heap_wanted > max_heap_size) THEN
BEGIN
vfmt_$write2( ';Heap allocated smaller than requested.%.', 0, 0 );
heap_size := max_heap_size;
END
ELSE IF (heap_wanted < min_heap_size) THEN
BEGIN
vfmt_$write2( ';Heap allocated larger than requested.%.', 0, 0 );
heap_size := min_heap_size;
END
ELSE
heap_size := heap_wanted;
END;
{ report size chosen }
IF heap_wanted_given OR leave_wanted_given THEN
vfmt_$write2( ';%LD bytes per heap, %LD bytes reserved%.'
, heap_size, space_to_leave );
END;
{ --------------------------------------------------------------------------- }
{ assembly code to do the jump to a random address }
PROCEDURE jump_to_t
( IN start_address: univ_ptr
; data_address: univ_ptr
; sfh_xenoid_dummy_slot: linteger
; stack_low: univ_ptr
; guard1
, guard2: univ_ptr
; p1: name_$pname_t
; lp1: linteger
; at1: univ_ptr
; p2: name_$pname_t
; lp2: linteger
; at2: univ_ptr
; heap_size: linteger
; debug: boolean
);
VAL_PARAM; EXTERN;
PROCEDURE start_t;
CONST
float_file = '~/tsystem/float.bin';
VAR
{ command line processing }
t_name: string;
t_namel: integer16;
cnt: integer;
heap_wanted, leave_wanted: linteger;
heap_p,
leave_p: boolean;
{ returned from loading t image }
start_address: univ_ptr;
data_address: univ_ptr;
{ heap allocation }
heap_size: linteger;
at1, at2: univ_ptr;
st: status_$t;
{ as inquiry }
dummy: integer;
as: as_$info_rec_t;
{ for pm_$load }
info: pm_$load_info;
BEGIN
cl_$init( [], 'bl', 2 );
debug := cl_$get_flag( '-d[ebug]', cnt );
verbose := cl_$get_flag( '-v[erbose]', cnt );
timing := cl_$get_flag( '-time[]', cnt );
use_streams := cl_$get_flag( '-streams[]', cnt );
heap_wanted := 0;
IF cl_$get_flag( '-h[eap]', cnt ) THEN
BEGIN
heap_p := true;
IF (cnt = 1) AND THEN (NOT cl_$get_num( heap_wanted )) THEN
heap_wanted := 0;
END
ELSE
heap_p := false;
leave_wanted := 0;
IF cl_$get_flag( '-l[eave]', cnt ) THEN
BEGIN
leave_p := true;
IF (cnt = 1) AND THEN (NOT cl_$get_num( leave_wanted )) THEN
leave_wanted := 0;
END
ELSE
leave_p := false;
IF NOT cl_$get_arg( cl_$first, t_name, t_namel, sizeof( string ) ) THEN
vfmt_$write2( 'Expecting T object file name%.', 0, 0 );
pm_$load( float_file, sizeof( float_file ), [pm_$install], 0, info, st );
IF st.all <> 0 THEN
die( 'installing floating point%$', st );
{ relocate t object file }
load_t_object_file( t_name, t_namel, start_address, data_address );
{ allocate heaps }
compute_heap_size( heap_wanted, leave_wanted, heap_p, leave_p, heap_size );
at1 := crtemp( heap_size, st );
IF st.all <> 0 THEN
die( 'creating/mapping first heap%$', st );
at2 := crtemp( heap_size, st );
IF st.all <> 0 THEN
die( 'creating/mapping first heap%$', st );
as_$get_info( as, sizeof( as ), dummy {actual size} );
vfmt_$write2( 'Jumping to t...%', 0, 0 );
jump_to_t( start_address
, data_address
, 0
, as.stack_low, as.guard1, as.guard2
, '', 0, at1 { ++++ flush it}
, '', 0, at2 { ++++ flush it}
, heap_size
, debug );
END;
BEGIN
start_t();
END.